#TreeSample
#Copyright Klaas Hartmann 2007, this program falls under the GNU GPLv2
#
#This is a GUI for the algorithms in Bio::Phylo::EvolutionaryModels. 
#It was created in a couple of days so the code in here is far from 
#perfect. For details regarding the algorithms please see the 
#Bio::Phylo::EvolutionaryModels package or the paper:
#
#Sampling trees from evolutionary models
#Klaas Hartmann, Dennis Wong, Tanja Gernhard
#Systematic Biology, in press

use strict;
use MyImages;

package MyFrame;
use threads;
use threads::shared;
use Wx qw[wxTE_MULTILINE wxTE_READONLY wxDefaultSize wxDefaultPosition wxCB_DROPDOWN wxCB_READONLY wxTAB_TRAVERSAL wxGA_HORIZONTAL wxDEFAULT_FRAME_STYLE wxFULL_REPAINT_ON_RESIZE wxICON_ERROR wxOK wxBITMAP_TYPE_PNG wxBITMAP_TYPE_BMP wxBITMAP_TYPE_ANY wxNOT_FOUND wxALIGN_RIGHT wxALIGN_CENTER_VERTICAL wxEXPAND wxTOP wxBOTTOM wxALIGN_CENTER_HORIZONTAL wxALIGN_BOTTOM wxALL wxVERTICAL wxHORIZONTAL wxRIGHT wxTEXT_ALIGNMENT_CENTRE wxTEXT_ALIGNMENT_JUSTIFIED wxTEXT_ALIGNMENT_LEFT wxICON_INFORMATION wxGA_SMOOTH];
use base 'Wx::Frame';
use POSIX qw(ceil floor);

use Bio::Phylo::IO 'parse';
use Bio::Phylo::EvolutionaryModels;
use wxAbout;

#The available algorithms
my @algorithms = ('Birth (Simplified GSA)','Birth and death (GSA)', 'Memoryless birth (PBMSA)', 'Constant rate birth and death (BDSA)','Incomplete sampling (Extended GSA)');
#The names for the algorithms
my @algorithms_int = ('b','bd','memoryless_b','constant_rate_bd','incomplete_sampling_bd');
#The following variables defined the options available for each algorithm and their properties
#Descriptive names
my @algorithm_options      = ('Sample size:','Tree size:','Threads:','Rate:','N Star','M Star','Sampling probability:');
#Initial values
my @algorithm_options_start= (1             ,10          ,1         ,1      ,20      ,15      ,.7                     );
#Internal names
my @algorithm_options_int  = ('sample_size' ,'tree_size', 'threads', 'rate', 'nstar', 'mstar', 'sampling_probability');
#Which algorithms the options apply to
my @algorithm_options_appl = ([1            ,1           ,1         ,1      ,0       ,0       ,0                      ],
                              [1            ,1           ,1         ,1      ,1       ,0       ,0                      ],
                              [1            ,1           ,1         ,0      ,0       ,0       ,0                      ],
                              [1            ,1           ,1         ,0      ,0       ,0       ,0                      ],
                              [1            ,1           ,1         ,1      ,1       ,1       ,1                      ]);
#The type of data of each option
my @algorithm_options_type = ('pint'        ,'pint'      ,'pint'    ,'preal','pint'  ,'pint'  ,'preal');
#Minimum values for each option
my @algorithm_options_min  = (1,            ,3           ,1         ,0      ,3       ,3       ,0);
#Helpful descriptions (for tooltips)
my @algorithm_options_description = ('The number of trees to sample',
                                     'The number of species that sampled trees should contain',
                                     'The number of threads to run (use 2 for a dual core processor, 4 for a quad core)',
                                     'The sampling rate, this needs to be deduced through experimentation',
                                     'The number of species after which the tree is sufficiently unlikely to return to Tree Size species (or M Star species for incomple sampling)',
                                     'The number of species after which it is sufficiently unlikely that incomplete sampling could have resulted in sampling Sample Size species)',
                                     'The probability of sampling any individual species');

#The same deal for the models
my @models = ('Yule', 'Constant rate birth and death', 'External model');
my %models_hash = ($models[0]=>0,$models[1]=>1,$models[2]=>2);
my @models_appl = ([1,0,1],[1,1,1],[1,0,0],[1,1,1],[1,1,1]);
my @models_int = (\&Bio::Phylo::EvolutionaryModels::constant_rate_birth, \&Bio::Phylo::EvolutionaryModels::constant_rate_birth_death,
\&Bio::Phylo::EvolutionaryModels::external_model);

my @model_options     =  ('Speciation rate:', 'Extinction rate:');
my @model_options_start= (1,                  0);
my @model_options_int =  ('birth_rate',       'death_rate');
my @model_options_appl=  ([1          ,       0],
                          [1          ,       1],
                          [0          ,       0]);
my @model_options_type = ('preal'     ,       'preal');
my @model_options_description = ('The speciation rate (parameter for exponential distribution)',
                                 'The extinction rate (parameter for exponential distribution)');


#The computation thread (the GUI thread should never be blocked)
my $compute_thread;
my $compute_thread;

my $a;

#An event for communicating with the GUI
my $DONE_EVENT : shared = Wx::NewEventType;

#Variables for returning data from the compute_thread
my @sampled_trees : shared = ();
my @sampled_diagnostics : shared = ();

my $frame;
my $count = 0;
my $time; 

sub new {
	my( $self, $parent, $id, $title, $pos, $size, $style, $name ) = @_;
	$parent = undef              unless defined $parent;
	$id     = -1                 unless defined $id;
	$title  = ""                 unless defined $title;
	$pos    = wxDefaultPosition  unless defined $pos;
	$size   = wxDefaultSize      unless defined $size;
	$name   = ""                 unless defined $name;

# begin wxGlade: MyFrame::new

	$style = wxDEFAULT_FRAME_STYLE 
		unless defined $style;

	$self = $self->SUPER::new( $parent, $id, $title, $pos, $size, $style, $name );
	$self->{panel_options_model} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, );
	$self->{sizer_6_staticbox} = Wx::StaticBox->new($self, -1, "Algorithm Options" );
	$self->{sizer_7_staticbox} = Wx::StaticBox->new($self, -1, "Model Options" );
	$self->{sizer_9_staticbox} = Wx::StaticBox->new($self, -1, "Output Options" );
	$self->{sizer_input_staticbox} = Wx::StaticBox->new($self, -1, "Input" );
	$self->{sizer_5_staticbox} = Wx::StaticBox->new($self, -1, "Output" );
	$self->{panel_options_algorithm} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, );
	

	# Menu Bar

	$self->{menubar} = Wx::MenuBar->new();
	$self->SetMenuBar($self->{menubar});
	my $wxglade_tmp_menu;
	$wxglade_tmp_menu = Wx::Menu->new();
	$self->{alg2} = $wxglade_tmp_menu->Append(Wx::NewId(), "Algorithm 2", "");
	$self->{alg3} = $wxglade_tmp_menu->Append(Wx::NewId(), "Algorithm 3", "");
	$self->{alg4} = $wxglade_tmp_menu->Append(Wx::NewId(), "Algorithm 4", "");
	$self->{alg5} = $wxglade_tmp_menu->Append(Wx::NewId(), "Algorithm 5", "");
	$self->{alg6} = $wxglade_tmp_menu->Append(Wx::NewId(), "Algorithm 6", "");
	$self->{menubar}->Append($wxglade_tmp_menu, "Examples");
	$wxglade_tmp_menu = Wx::Menu->new();
	$self->{help_overview} = $wxglade_tmp_menu->Append(Wx::NewId(), "Overview", "");
	$self->{help_about} = $wxglade_tmp_menu->Append(Wx::NewId(), "About", "");
	$self->{help_license} = $wxglade_tmp_menu->Append(Wx::NewId(), "License", "");
	$self->{menubar}->Append($wxglade_tmp_menu, "Help");
	
# Menu Bar end

	$self->{label_algorithm} = Wx::StaticText->new($self, -1, "Type:", wxDefaultPosition, wxDefaultSize, );
	$self->{combo_box_algorithm} = Wx::ComboBox->new($self, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_DROPDOWN|wxCB_READONLY);
	$self->{button_help_algorithm} = Wx::Button->new($self, -1, "?");
	$self->{label_1} = Wx::StaticText->new($self, -1, "Type:", wxDefaultPosition, wxDefaultSize, );
	$self->{combo_box_model} = Wx::ComboBox->new($self, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_DROPDOWN|wxCB_READONLY);
	$self->{button_help_model} = Wx::Button->new($self, -1, "?");
	$self->{label_4} = Wx::StaticText->new($self, -1, "Precision:", wxDefaultPosition, wxDefaultSize, );
	$self->{panel_2} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, );
	$self->{combo_box_1} = Wx::ComboBox->new($self, -1, "", wxDefaultPosition, wxDefaultSize, ["1", "0.1", "0.01", "0.001", "0.0001", "0.00001", "0.000001"], wxCB_DROPDOWN|wxCB_READONLY);
	$self->{button_help_output} = Wx::Button->new($self, -1, "?");
	$self->{checkbox_extinct} = Wx::CheckBox->new($self, -1, "Keep extinct species", wxDefaultPosition, wxDefaultSize, );
	$self->{button_sample} = Wx::Button->new($self, -1, "Sample!");
	$self->{gauge} = Wx::Gauge->new($self, -1, 10, wxDefaultPosition,     wxDefaultSize, wxGA_HORIZONTAL|wxGA_SMOOTH);
	$self->{panel_tree} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxFULL_REPAINT_ON_RESIZE);
	$self->{label_input_trees} = Wx::StaticText->new($self, -1, "Simulated trees:", wxDefaultPosition, wxDefaultSize, );
	$self->{text_input_trees} = Wx::TextCtrl->new($self, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
	$self->{label_2} = Wx::StaticText->new($self, -1, "Trees:", wxDefaultPosition, wxDefaultSize, );
	$self->{text_trees} = Wx::TextCtrl->new($self, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY);
	$self->{label_3} = Wx::StaticText->new($self, -1, "Diagnostic Information:", wxDefaultPosition, wxDefaultSize, );
	$self->{text_diagnostics} = Wx::TextCtrl->new($self, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY);

	$self->__set_properties();
	$self->__do_layout();

# end wxGlade
	Wx::Event::EVT_COMBOBOX($self, $self->{combo_box_algorithm}->GetId, \&algorithm_selected);
	Wx::Event::EVT_COMBOBOX($self, $self->{combo_box_model}->GetId, \&model_selected);
        Wx::Event::EVT_PAINT($self->{panel_tree},  \&OnPaint);
        Wx::Event::EVT_BUTTON($self, $self->{button_sample}, \&sample);
        Wx::Event::EVT_COMMAND($self, -1, $DONE_EVENT, \&sampling_done );
        Wx::Event::EVT_MENU($self, $self->{help_about}->GetId, \&help_about);
        Wx::Event::EVT_MENU($self, $self->{help_license}->GetId, \&help_license);
        Wx::Event::EVT_MENU($self, $self->{help_overview}->GetId, \&help_overview);
        Wx::Event::EVT_MENU($self, $self->{alg2}->GetId, \&load_example);
        Wx::Event::EVT_MENU($self, $self->{alg3}->GetId, \&load_example);
        Wx::Event::EVT_MENU($self, $self->{alg4}->GetId, \&load_example);
        Wx::Event::EVT_MENU($self, $self->{alg5}->GetId, \&load_example);
        Wx::Event::EVT_MENU($self, $self->{alg6}->GetId, \&load_example);
	Wx::Event::EVT_BUTTON($self, $self->{button_help_algorithm}->GetId, \&help_algorithm);
	Wx::Event::EVT_BUTTON($self, $self->{button_help_model}->GetId, \&help_model);
	Wx::Event::EVT_BUTTON($self, $self->{button_help_output}->GetId, \&help_output);
        $self->{combo_box_algorithm}->SetSelection(0);
        $self->algorithm_selected;
        $frame = $self;
	return $self;

}

sub sample {
    my ($self, $event) = @_;
#    $event->Skip();
    #KH1
    if (defined $compute_thread && $self->{button_sample}->GetLabel() eq 'Cancel') {
        $compute_thread->kill('KILL')->detach();
        $self->{button_sample}->SetLabel('Sample!');
        $compute_thread = undef;
        return;
    }
    $self->{text_trees}->Clear();
    $self->{text_diagnostics}->Clear();

    $time = time;

    my $algorithm = $self->{combo_box_algorithm}->GetSelection();
    my $model = $models_hash{$self->{combo_box_model}->GetStringSelection()};

    my $errors = '';
    my %algorithm_option_values;
    my %model_option_values;
    my $n_errors = 0;
    for (my $i = 0; $i < scalar @algorithm_options; $i++) {
        next unless $algorithm_options_appl[$algorithm]->[$i];
        my $value = $self->{options}->{$algorithm_options_int[$i]}->GetValue();

        my ($positive, $integer) = (0,0);

        $positive = 1 if $algorithm_options_type[$i] eq 'preal';
        $positive = 1 if $algorithm_options_type[$i] eq 'pint';
        $integer = 1 if $algorithm_options_type[$i] eq 'pint';

        if ($positive && $value < 0) {
            $errors .= $algorithm_options[$i]." must be positive\n";
            $n_errors++;
        }

        if ($value < $algorithm_options_min[$i]) {
            $errors .= $algorithm_options[$i]." must be at least ".$algorithm_options_min[$i]."\n";
            $n_errors++;
        }

        if ($integer && int($value) != $value) {
            $errors .= $algorithm_options[$i]." must be an integer\n";
            $n_errors++;
        }
        $algorithm_option_values{$algorithm_options_int[$i]} = $value;
    }
    for (my $i = 0; $i < scalar @model_options; $i++) {
        next unless $model_options_appl[$model]->[$i];
        my $value = $self->{model_options}->{$model_options_int[$i]}->GetValue();

        my ($positive, $integer) = (0,0);

        $positive = 1 if $model_options_type[$i] eq 'preal';
        $positive = 1 if $model_options_type[$i] eq 'pint';
        $integer = 1 if $model_options_type[$i] eq 'pint';

        if ($positive && $value < 0) {
            $errors .= $model_options[$i]." must be positive\n";
            $n_errors++;
        }

        if ($integer && int($value) != $value) {
            $errors .= $model_options[$i]." must be an integer\n";
            $n_errors++;
        }
        $model_option_values{$model_options_int[$i]} = $value;
    }

    if ($errors) {
        my $dlg;
        if ($n_errors>1) {
            $dlg = Wx::MessageDialog->new($self,
                                            "There were some problems with the parameters:\n\n".$errors."\nPlease fix these and try again.\n\n",
                                            'Parameter problems',
                                            wxICON_ERROR|wxOK);
        } else {
            $dlg = Wx::MessageDialog->new($self,
                                            "There was a problem with one of the parameters:\n\n".$errors."\nPlease fix this and try again.\n\n",
                                            'Parameter problem',
                                            wxICON_ERROR|wxOK);
        }
        $dlg->ShowModal();
        return;
    }

    my @main = ('tree_size','sample_size','threads','remove_extinct');
    my %main_options;
    foreach (@main) {
        $main_options{$_} = $algorithm_option_values{$_};
        delete $algorithm_option_values{$_};
    }

    my %options = (algorithm => $algorithms_int[$algorithm], 
                                                        model => $models_int[$model],
                                                        algorithm_options => {%algorithm_option_values}, 
                                                        %main_options,
                                                        model_options => \%model_option_values,
                                                        output_format => 'newick');

    #If we have the memoryless birth model we specify the pendant edge distribution for the Yule model
    if ($algorithm == 2) {
        my $random_pendant_function = sub { 
            %options = @_;
            return -log(rand)/$options{birth_rate}/$options{tree_size};
        };
        $options{algorithm_options}->{pendant_dist} = $random_pendant_function;
    }

    my @trees;
    #If we are using trees from an external model
    if ($self->{combo_box_model}->GetStringSelection() eq 'External model') {
        my $treestring = $self->{text_input_trees}->GetValue();
        foreach ($treestring =~ /[^;]+/g) {
            next unless $_;
            push(@trees,$_.";");
            if ($@) {
                my $dlg = Wx::MessageDialog->new($self,
                                            "There was a problem with the Newick string:\n\n".$trees[-1]."\nPlease fix this and try again. Hint: ensure each tree has a trailing ;",
                                            'Input format problem',
                                            wxICON_ERROR|wxOK);
                $dlg->ShowModal();
               return;
            }
        }
        unless (scalar @trees) {
                my $dlg = Wx::MessageDialog->new($self,
                                            "You did not enter any valid input trees:\n\nPlease fix this and try again.",
                                            'No input trees',
                                            wxICON_ERROR|wxOK);
                $dlg->ShowModal();
                return;
        }

        $options{model_options}->{trees} = \@trees;

    }

    @_ = ();
    $count = 0;
    $self->{gauge}->SetValue(0);
    $self->{gauge}->SetRange(int($options{sample_size}*1.10));
#    my @result = (Bio::Phylo::EvolutionaryModels::sample(%options));
    ($compute_thread) = threads->new(\&sampleTreesWrapper, %options);
    $self->{button_sample}->SetLabel('Cancel');

}


sub sampling_done {
    my ($self,$event) = @_;

    my $data = $event->GetData();

    if ($data) {
        $count += $data;
        $self->{gauge}->SetValue($count);
        return;
    }
    $self->{text_trees}->Clear();
    $compute_thread->detach();
    $compute_thread = undef;

    my $index = 0;
    foreach(@sampled_trees) {
        $index++;
        $self->{gauge}->SetValue($count+int($index*.1));
        $self->{text_trees}->AppendText($_."\n\n");
    }
    $self->{button_sample}->SetLabel('Sample!');
    $time = time()-$time;
    $self->{text_diagnostics}->Clear();
    $self->{text_diagnostics}->AppendText("Time elapsed: $time seconds\n\n");

    my @count;
    return unless @sampled_diagnostics;
    foreach(@sampled_diagnostics) {
        $count[floor($_)]++;
    }
    $self->{text_diagnostics}->AppendText("Expected samples    \tNumber of occurrences\n");
    for (my $i = 0; $i < @count; $i++) {
        $self->{text_diagnostics}->AppendText("[$i,".($i+1).")                           \t".$count[$i]."\n");

    }

#FAILED TO GET SLIDERS TO GO TO START... OH WELL.
#    $self->{text_trees}->SetScrollPos(wxVERTICAL,0,1);
#    $self->{text_trees}->SetScrollPos(wxVERTICAL,0,1);
#    $self->{text_diagnostics}->SetScrollPos(wxVERTICAL,0,1);


}



sub sampleTreesWrapper {
    my %options = @_;

    $options{counter}=\&update_count;

    # Thread 'cancellation' signal handler
    $SIG{'KILL'} = sub { threads->exit(); };

    my @result = (Bio::Phylo::EvolutionaryModels::sample(%options));

    @sampled_trees = (@{$result[0]});
    @sampled_diagnostics = (@{$result[1]});

    
    my $end = new Wx::PlThreadEvent( -1, $DONE_EVENT, 0 );
    Wx::PostEvent( $frame, $end );
}

sub update_count {
    my $update = new Wx::PlThreadEvent( -1, $DONE_EVENT, shift );
    Wx::PostEvent( $frame, $update );
    return defined $compute_thread;
}

sub OnPaint {
    my ($self, $event) = @_;
    my $drawArea;
    #Depending whether the event is being called due to a repaint or 
    # change in content (eg. image) we use different DC objects. Unsure 
    # how important this really is
    if (defined $event)
    {
        $drawArea = Wx::PaintDC->new($self);
    } else {
        $drawArea = Wx::ClientDC->new($self );
    }

    #initialise all the image handlers
    Wx::InitAllImageHandlers();


    #Get a dc object
    $drawArea = Wx::ClientDC->new($self);

    my ($w, $h) = $self->GetSizeWH();

    #load the image
    my $wxbitmap = Wx::Bitmap->new(MyImages::load_image("darwin_tree_lg.png"),wxBITMAP_TYPE_PNG);
    if ($h < $wxbitmap->GetHeight) {
        my $image = $wxbitmap->ConvertToImage();
        $image->Rescale($wxbitmap->GetWidth*$h/$wxbitmap->GetHeight,$h);
        $wxbitmap = Wx::Bitmap->new($image);
    }
    my $x_pos = ($w-$wxbitmap->GetWidth)/2;
    my $y_pos = $h-$wxbitmap->GetHeight();


    #Draw the bitmap
    $drawArea->DrawBitmap($wxbitmap,$x_pos,$y_pos,0);

    if (defined $event) { $event->Skip(); }
}
sub __set_properties {
	my $self = shift;

# begin wxGlade: MyFrame::__set_properties

	$self->SetTitle("TreeSample");
	$self->SetBackgroundColour(Wx::Colour->new(239, 239, 239));
	$self->{combo_box_algorithm}->SetToolTipString("Choose a sampling algorithm. Numbers in brackets refer to the algorithms in \"Sampling trees from evolutionary models\"");
	$self->{combo_box_algorithm}->SetSelection(-1);
	$self->{button_help_algorithm}->SetMinSize(Wx::Size->new(20, 25));
	$self->{combo_box_model}->SetToolTipString("Please select a model from which to sample");
	$self->{combo_box_model}->SetSelection(-1);
	$self->{button_help_model}->SetMinSize(Wx::Size->new(20, 25));
	$self->{label_4}->Show(0);
	$self->{combo_box_1}->SetMinSize(Wx::Size->new(100, 25));
	$self->{combo_box_1}->SetToolTipString("The precision of the edge lengths for the newick output");
	$self->{combo_box_1}->Show(0);
	$self->{combo_box_1}->SetSelection(2);
	$self->{button_help_output}->SetMinSize(Wx::Size->new(20, 25));
	$self->{button_help_output}->Show(0);
	$self->{checkbox_extinct}->SetToolTipString("Some algorithms/models can include extinct species (leaves that end prior to the present). ");
	$self->{checkbox_extinct}->Show(0);
	$self->{button_sample}->SetToolTipString("Sample the trees");
	$self->{panel_tree}->SetToolTipString("The first phylogenetic tree, by Charles Darwin");

# end wxGlade
    #Add the algorithms
    foreach (@algorithms) {
        $self->{combo_box_algorithm}->Append($_);
    }

    #Set the icon
    my $icon = Wx::Icon->new();
    my $file = MyImages::load_image('Bonsai1.ico');
    if ($file) {
        my $iconbundle = Wx::IconBundle->new($file,wxBITMAP_TYPE_ANY);
        $self->SetIcons($iconbundle);
    }

}

sub algorithm_selected {
    my ($self,$event) = @_;
    $event->Skip() if defined $event;

    $self->{combo_box_model}->Clear();
    my $algorithm = $self->{combo_box_algorithm}->GetSelection();
    return if $algorithm eq wxNOT_FOUND;
    
    for (my $index = 0; $index < @models; $index++) {
        $self->{combo_box_model}->Append($models[$index]) if $models_appl[$algorithm]->[$index];
    }
    $self->{combo_box_model}->SetSelection(0);
    $self->{grid_options_algorithm}->Clear(0);
    foreach (values %{$self->{options}}) { $_->Hide(); }
    for (my $i = 0; $i < @algorithm_options; $i++) {
        next unless $algorithm_options_appl[$algorithm]->[$i];

        #Create the text box
        unless (defined $self->{options}->{$algorithm_options_int[$i]}) {
            $self->{options}->{$algorithm_options_int[$i]} = Wx::TextCtrl->new($self->{panel_options_algorithm}, -1, $algorithm_options_start[$i], wxDefaultPosition, wxDefaultSize);
            $self->{options}->{'Label'.$algorithm_options_int[$i]} = Wx::StaticText->new($self->{panel_options_algorithm},-1,$algorithm_options[$i],wxDefaultPosition,wxDefaultSize,wxALIGN_RIGHT);
            
        }
        
        my $textctrl = $self->{options}->{$algorithm_options_int[$i]};

        my $labelctrl = $self->{options}->{'Label'.$algorithm_options_int[$i]};
        $textctrl->Show();
        $labelctrl->Show();
        $textctrl->SetToolTip($algorithm_options_description[$i]);
        $labelctrl->SetToolTip($algorithm_options_description[$i]);
        $self->{grid_options_algorithm}->Add($labelctrl,0,wxALIGN_CENTER_VERTICAL);
        $self->{grid_options_algorithm}->Add($textctrl,0,wxALIGN_CENTER_VERTICAL|wxEXPAND);
    }
    $self->Layout();
    $self->model_selected();


}

sub model_selected {
    my ($self,$event) = @_;
    $event->Skip() if defined $event;
    my $model = $self->{combo_box_model}->GetSelection();

    return if $model eq wxNOT_FOUND;
    $model = $models_hash{$self->{combo_box_model}->GetStringSelection()};
    $self->{grid_options_model}->Clear(0);
    foreach (values %{$self->{model_options}}) { $_->Hide(); }
    for (my $i = 0; $i < @model_options; $i++) {
        next unless $model_options_appl[$model]->[$i];

        #Create the text box
        unless (defined $self->{model_options}->{$model_options_int[$i]}) {
            $self->{model_options}->{$model_options_int[$i]} = Wx::TextCtrl->new($self->{panel_options_model}, -1, $model_options_start[$i], wxDefaultPosition, wxDefaultSize);
            $self->{model_options}->{'Label'.$model_options_int[$i]} = Wx::StaticText->new($self->{panel_options_model},-1,$model_options[$i],wxDefaultPosition,wxDefaultSize,wxALIGN_RIGHT);
            
        }
        
        my $textctrl = $self->{model_options}->{$model_options_int[$i]};

        my $labelctrl = $self->{model_options}->{'Label'.$model_options_int[$i]};
        $textctrl->Show();
        $labelctrl->Show();
        $textctrl->SetToolTip($model_options_description[$i]);
        $labelctrl->SetToolTip($model_options_description[$i]);
        $self->{grid_options_model}->Add($labelctrl,0,wxALIGN_CENTER_VERTICAL);
        $self->{grid_options_model}->Add($textctrl,0,wxALIGN_CENTER_VERTICAL|wxEXPAND);
    }

    #If external model show tree input otherwise hide
    my $show = $self->{combo_box_model}->GetStringSelection() eq 'External model';
    $self->{sizer_input_staticbox}->Show($show);
    $self->{text_input_trees}->Show($show);
    $self->{label_input_trees}->Show($show);
    if ($show) {
        $self->{sizer_right}->Insert(0,$self->{sizer_input},1,wxEXPAND,0);
    } else {
        $self->{sizer_right}->Detach($self->{sizer_input});
    }
    $self->Layout();
    $self->Refresh();
}

sub __do_layout {
	my $self = shift;

# begin wxGlade: MyFrame::__do_layout

	$self->{sizer_main} = Wx::BoxSizer->new(wxHORIZONTAL);
	$self->{sizer_right} = Wx::BoxSizer->new(wxVERTICAL);
	$self->{sizer_5}= Wx::StaticBoxSizer->new($self->{sizer_5_staticbox}, wxVERTICAL);
	$self->{sizer_input}= Wx::StaticBoxSizer->new($self->{sizer_input_staticbox}, wxVERTICAL);
	$self->{sizer_1} = Wx::BoxSizer->new(wxVERTICAL);
	$self->{sizer_9}= Wx::StaticBoxSizer->new($self->{sizer_9_staticbox}, wxVERTICAL);
	$self->{sizer_2_copy} = Wx::BoxSizer->new(wxHORIZONTAL);
	$self->{sizer_8} = Wx::BoxSizer->new(wxHORIZONTAL);
	$self->{sizer_7}= Wx::StaticBoxSizer->new($self->{sizer_7_staticbox}, wxVERTICAL);
	$self->{grid_options_model} = Wx::GridSizer->new(0, 2, 0, 0);
	$self->{sizer_3} = Wx::BoxSizer->new(wxHORIZONTAL);
	$self->{sizer_6}= Wx::StaticBoxSizer->new($self->{sizer_6_staticbox}, wxVERTICAL);
	$self->{grid_options_algorithm} = Wx::GridSizer->new(0, 2, 0, 0);
	$self->{sizer_4} = Wx::BoxSizer->new(wxHORIZONTAL);
	$self->{sizer_4}->Add($self->{label_algorithm}, 0, wxRIGHT|wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5);
	$self->{sizer_4}->Add($self->{combo_box_algorithm}, 1, wxTOP|wxBOTTOM|wxEXPAND|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5);
	$self->{sizer_4}->Add($self->{button_help_algorithm}, 0, wxALIGN_CENTER_VERTICAL, 0);
	$self->{sizer_6}->Add($self->{sizer_4}, 0, wxEXPAND, 0);
	$self->{panel_options_algorithm}->SetSizer($self->{grid_options_algorithm});
	$self->{sizer_6}->Add($self->{panel_options_algorithm}, 0, wxEXPAND, 0);
	$self->{sizer_1}->Add($self->{sizer_6}, 0, wxEXPAND, 0);
	$self->{sizer_3}->Add($self->{label_1}, 0, wxRIGHT|wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5);
	$self->{sizer_3}->Add($self->{combo_box_model}, 1, wxTOP|wxBOTTOM|wxEXPAND|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5);
	$self->{sizer_3}->Add($self->{button_help_model}, 0, wxALIGN_CENTER_VERTICAL, 0);
	$self->{sizer_7}->Add($self->{sizer_3}, 0, wxEXPAND, 0);
	$self->{panel_options_model}->SetSizer($self->{grid_options_model});
	$self->{sizer_7}->Add($self->{panel_options_model}, 0, wxEXPAND, 0);
	$self->{sizer_1}->Add($self->{sizer_7}, 0, wxTOP|wxBOTTOM|wxEXPAND, 5);
	$self->{sizer_8}->Add($self->{label_4}, 0, wxALIGN_CENTER_VERTICAL, 0);
	$self->{sizer_8}->Add($self->{panel_2}, 5, wxEXPAND, 0);
	$self->{sizer_8}->Add($self->{combo_box_1}, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5);
	$self->{sizer_8}->Add($self->{button_help_output}, 0, wxALIGN_CENTER_VERTICAL, 0);
	$self->{sizer_9}->Add($self->{sizer_8}, 0, wxTOP|wxBOTTOM|wxEXPAND, 5);
	$self->{sizer_9}->Add($self->{checkbox_extinct}, 0, wxALIGN_RIGHT|wxALIGN_CENTER_HORIZONTAL, 0);
	$self->{sizer_2_copy}->Add($self->{button_sample}, 0, wxRIGHT|wxALIGN_CENTER_HORIZONTAL, 5);
	$self->{sizer_2_copy}->Add($self->{gauge}, 1, wxEXPAND, 0);
	$self->{sizer_9}->Add($self->{sizer_2_copy}, 0, wxEXPAND, 0);
	$self->{sizer_1}->Add($self->{sizer_9}, 0, wxEXPAND, 0);
	$self->{sizer_1}->Add($self->{panel_tree}, 1, wxTOP|wxEXPAND|wxALIGN_BOTTOM|wxALIGN_CENTER_HORIZONTAL, 5);
	$self->{sizer_main}->Add($self->{sizer_1}, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 10);
	$self->{sizer_input}->Add($self->{label_input_trees}, 0, 0, 0);
	$self->{sizer_input}->Add($self->{text_input_trees}, 1, wxEXPAND, 0);
	$self->{sizer_right}->Add($self->{sizer_input}, 1, wxALL|wxEXPAND, 0);
	$self->{sizer_5}->Add($self->{label_2}, 0, 0, 0);
	$self->{sizer_5}->Add($self->{text_trees}, 4, wxBOTTOM|wxEXPAND, 5);
	$self->{sizer_5}->Add($self->{label_3}, 0, wxTOP, 5);
	$self->{sizer_5}->Add($self->{text_diagnostics}, 1, wxEXPAND, 0);
	$self->{sizer_right}->Add($self->{sizer_5}, 2, wxALL|wxEXPAND, 0);
	$self->{sizer_main}->Add($self->{sizer_right}, 1, wxRIGHT|wxTOP|wxBOTTOM|wxEXPAND, 10);
	$self->SetSizer($self->{sizer_main});
	$self->{sizer_main}->Fit($self);
	$self->Layout();

# end wxGlade

    #Set the windows size properties
    $self->SetMinSize(Wx::Size->new(640,480));
    $self->SetSize(Wx::Size->new(800,600));
    $self->{sizer_right}->Detach($self->{sizer_input});
    $self->{sizer_input_staticbox}->Hide;
    $self->{text_input_trees}->Hide;
    $self->{label_input_trees}->Hide;

    #$self->{sizer_right}->Hide($self->{sizer_input},1);

    #$self->{sizer_input
    #Make the tree input disappear

    $self->Layout();
}

#Displays the help -> about box
sub help_about {
	my ($self,$event) = @_;
	$event->Skip();

	my $frame = wxAbout->new($self,-1,'About TreeSample',wxDefaultPosition,Wx::Size->new(600,335));
	my $text = $frame->get_text;
	$text->BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
	$text->Newline;
	$text->BeginFontSize(14);
	$text->BeginBold;
	$text->WriteText("TreeSample\n");
	$text->EndBold;
	$text->EndFontSize;
	$text->WriteText("Copyright 2007, Klaas Hartmann\n");
	$text->EndAlignment;	
	$text->Newline;
	$text->BeginAlignment(wxTEXT_ALIGNMENT_JUSTIFIED);
	$text->WriteText("TreeSample is an interface to algorithms for sampling phylogenetic trees from evolutionary models. The main focus is to correctly sample trees of given sizes. The algorithms implemented here are described in:\n\nSampling trees from evolutionary models\nKlaas Hartmann, Dennis Wong, Tanja Gernhard\nSystematic Biology, in press"); 
	$text->Newline;
	$text->Newline;
	$text->WriteText("The algorithms are available in the Perl module Bio::Phylo::EvolutionaryModels. If you wish to sample from models other than those in the interface, these can easily be added to that module. If you need help implementing your model of interest contact me, if its not too complicated I may be able to quickly implement it for you. Any algorithms or models added by/for other authors will have their full citation details listed here, so don't be shy about contributing!"); 
	$frame->ShowModal;
		
}


#Displays the help -> license box
sub help_license {
	my ($self,$event) = @_;
	$event->Skip();
	my $frame = wxAbout->new($self,-1,'TreeSample License');
	my $text = $frame->get_text;
		$text->BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
	$text->Newline;
	$text->BeginFontSize(14);
	$text->BeginBold;
	$text->WriteText("TreeSample\n");
	$text->EndBold;
	$text->EndFontSize;
	$text->WriteText("Copyright 2007, Klaas Hartmann\n");
	$text->EndAlignment;	
	$text->Newline;
	$text->BeginAlignment(wxTEXT_ALIGNMENT_LEFT);
	$text->WriteText("TreeSample is distributed under the GNU GPL license (see below). If you use this program in your work please cite:\n\nREF TO GO HERE\n\nAlgorithms and models contributed by other authors will also have their citation details placed here. So don't be shy about contributing!\n\n");
        my $gpl_file = MyImages::load_image("gpl.txt");
	open (GPL, "+<$gpl_file");

 	my @gpl = <GPL>;
	seek GPL,0,0;

	my $gpl = '';
	 foreach  (@gpl){
#	 	$_ =~ s/\n//g;
	 	$gpl .= $_;
	 }
     $text->WriteText($gpl);

	$frame->ShowModal;
			
}

#Displays the help -> overview box
sub help_overview {
	my ($self,$event) = @_;
	$event->Skip();
	my $frame = wxAbout->new($self,-1,'TreeSample Overview');
	my $text = $frame->get_text;
		$text->BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
	$text->Newline;
	$text->BeginFontSize(14);
	$text->BeginBold;
	$text->WriteText("TreeSample\n");
	$text->EndBold;
	$text->EndFontSize;
	$text->WriteText("Copyright 2007, Klaas Hartmann\n");
	$text->EndAlignment;	
	$text->Newline;
	$text->BeginAlignment(wxTEXT_ALIGNMENT_LEFT);
	$text->WriteText("TreeSample provides an interface to algorithms for sampling phylogenetic trees from evolutionary models. The main focus is sampling trees of a given size but it is also possible to sample trees of a given age (although this is trivial).\n\nFirst select an algorithm and enter the relevant options. You may need to refer to the paper to understand some of the options. The threads option is useful for multi-processor systems, it splits the sampling work into the specified number of threads thereby utilising up to that many processors.\n\nNext select the model from which you wish to sample. At present only some very basic models are included and these are available only for the algorithms which can sample from them. To sample from other models either\n1) implement them in Perl and use Bio::Phylo::EvolutionaryModels instead of TreeSample\n2) or contact me (Klaas Hartmann), if your model is fairly simple I may be able to implement it for you.\n\nFinally press Sample!, the progress bar will indicate the number of sampled trees (at the end there is a slight delay as the results are compiled). At any point you may cancel the sampling procedure. The diagnostics contains some (hopefully) useful information about the sampling procedure, in particular the number of samples obtained for each simulated tree may be useful for deciding sampling rates for some models.");

	$frame->ShowModal;
			
}

sub load_example {
    my ($self,$event) = @_;
    $event->Skip();
    my $index = -1;

    my @examples = ('alg2','alg3','alg4','alg5','alg6');

    for (my $i = 0; $i < @examples; $i++) {
        $index = $i if $self->{$examples[$i]}->GetId == $event->GetId;
    }
    return if $index == -1;

#   my @algorithm_options      = ('Sample size:','Tree size:','Threads:','Rate:','N Star','M Star','Sampling probability:');
#   Algorithm options
    my @algorithm_options_example= (20            ,10          ,2         ,6      ,30      ,20      ,.8                     );

    $self->{combo_box_algorithm}->SetSelection($index);
    $self->algorithm_selected;
    $self->{combo_box_model}->SetSelection($self->{combo_box_model}->GetCount()-2);
    $self->model_selected;

    for (my $i = 0; $i < @algorithm_options; $i++) {
        next unless defined $self->{options}->{$algorithm_options_int[$i]};
        $self->{options}->{$algorithm_options_int[$i]}->SetValue($algorithm_options_example[$i]);
    }
    if (defined $self->{model_options}->{birth_rate}) {
        $self->{model_options}->{birth_rate}->SetValue(1);
    }
    if (defined $self->{model_options}->{death_rate}) {
        $self->{model_options}->{death_rate}->SetValue(0.8);
    }

}

#Help command button
sub help_algorithm {
	my ($self, $event) = @_;
#	$event->Skip();

	my $info = <<HEREDOC;
Here you can select an algorithm to use. Different algorithms apply to different models and are described in:

Sampling trees from evolutionary models
Klaas Hartmann, Dennis Wong, Tanja Gernhard
Systematic Biology, in press

For constant rate birth and death processes the fastest algorithm is algorithm 5. This excludes any extinct species. If you want extinct species in your tree use algorithm 3. 

For algorithms 2,3 and 6 you will have to play with the sampling rate. The goal here is to set the rate so that few simulated trees have more than one sample and few simulated trees have no samples.

The threads option enables you to make use of all available processors on your machine. Generally set this to the number of processors you have for optimal performance (eq. 2 for a core duo)

For help with other parameters please refer to the paper.

HEREDOC
	my $pd_title = "Sampling algorithms\n";

	my $dialog = Wx::MessageDialog->new($self,
	    $info,
	    "Problem Types Help",
	    wxOK | wxICON_INFORMATION);
	$dialog->ShowModal();

		
}

#Help command button
sub help_model {
	my ($self, $event) = @_;
#	$event->Skip();

	my $info = <<HEREDOC;
Here you can select a model from which to sample trees:

Constant rate birth and constant rate birth and death models are built-in and can be used directly.

Trees simulated with external methods can be used by selecting "External Model". Please ensure that the trees satisfy the criteria for the sampling approach as outlined in the paper (see Help->About) and the manual for Bio::Phylo::EvolutionaryModels. Trees should be entered as Newick strings. For best results there should be more trees inputted than you are sampling by an order of magnitude.

Alternatively you can implement your model in Perl and use the algorithms as implemented in the Perl Bio::Phylo::EvolutionaryModels package.

Lastly I am keen to see this software used, so if you have a simple, well-defined model I may be able to implement and sample from it for you. Contact me (Klaas Hartmann) for more details (see my website www.klaashartmann.com for my current contact details).

HEREDOC
	my $pd_title = "Models\n";

	my $dialog = Wx::MessageDialog->new($self,
	    $info,
	    "Problem Types Help",
	    wxOK | wxICON_INFORMATION);
	$dialog->ShowModal();

		
}

#Help command button
sub help_output {
	my ($self, $event) = @_;
#	$event->Skip();

	my $info = <<HEREDOC;
Here you can select options for the output and start the sampling process. Once started the sampling process can be aborted at any time.

The precision is currently unimplemented!

HEREDOC
	my $pd_title = "Output\n";

	my $dialog = Wx::MessageDialog->new($self,
	    $info,
	    "Problem Types Help",
	    wxOK | wxICON_INFORMATION);
	$dialog->ShowModal();

		
}


1;

1;

package main;

#unless(caller){
	local *Wx::App::OnInit = sub{1};
	my $app = Wx::App->new();
	Wx::InitAllImageHandlers();

	my $TreeSampler = MyFrame->new();

	$app->SetTopWindow($TreeSampler);
	$TreeSampler->Show(1);
	$app->MainLoop();
#}
